Copyright ã1995 by NeXT Computer, Inc.  All Rights Reserved.

DBBinder

Inherits From:	Object

Conforms To:	DBCursorPositioning

Declared In:	dbkit/DBBinder.h

Class Description

The DBBinder class provides a mechanism for connecting individual data items in a database to particular objects, variables, and methods in your application.  Most applications benefit by avoiding DBBinder and working instead with higher-level classes such as DBRecordList or DBRecordStream.  You should create and use DBBinder objects only if your application needs to augment or modify the functionality provided by DBRecordStream or DBRecordList.

Preparing a DBBinder

To access a database, a DBBinder must be initialized and associated with a database model through a DBDatabase object, as shown below:

/* Initialize the DBBinder through the init method.  */
DBBinder *myBinder = [[DBBinder alloc] init];

/* Associate it with a DBDatabase through the setDatabase: method.  */
[myBinder setDatabase:myDB];

Furthermore, the DBBinder must be informed of which properties in which tables in the database it should accommodate.  There are two ways to do this:

·	If you can determine the list of properties that you're interested in, you should inform the DBBinder through the setProperties: method.  As a convenience, the initForDatabase:withProperties:andQualifier: method lets you initialize the DBBinder and set its DBDatabase and property list (and an optional property qualifier) in a single breath.  An example of this method is given in the next section.

·	Alternatively, you can describe the properties that you want as an expression in the database's query language, passing the expression (a string) as the argument to the evaluateString: method, as shown below:

/* Select all the properties in the "Weight" table.  */ 
[myBinder evaluateString:"select * in Weight"];

The optional qualifier described as part of the initForDatabase:...  method can be set separately, through the setQualifier: method.  The qualifier, of which there can be but one at a time per DBBinder, is used to filter properties when the DBBinder is told to select data from the database.  (See the ªQualificationº section, below for more on the qualifier.)

Records and Containers

The pith of a DBBinder is a collection of objects that hold records from a database table. Each object, called a record, holds one record from the database.  The collection of a DBBinder's record-holding objects is stored in a container object.  Record and container objects, however, aren't built into the DBBinder classÐyou have to specify what sorts of objects you want to assume these two roles.

Specifying a container is easy, you invoke the setContainer: method, passing an object that conforms to the DBContainers protocol.  That object will be used by the DBBinder to store record objects when the DBBinder fetches from the database.  Barring any specialized requirements, a DBBinder is well served using a List object as its container (DBBinder defines a List category that allows a List to pose as a DBContainers-conforming object).  You can also use a DBBinder without setting its container.  For a container-less DBBinder, fetching data is done one record at a time and can only step forward through the database.

Setting a record object takes a bit more thought.  There are two general approaches:  You can specify an object yourself that will be copied for each record, or you can let the DBBinder create and assemble a class dynamically, instances of which it will then create to store records.  

The first approach centers around the setRecordPrototype: method.  To this method you pass an object that will be copied as records are fetched from the table, one copy per record.  But you're not done yet.  To actually get a record's property values into a copy of the prototype record object, you must create an association between each property and one of the record object's instance variables, or between a property and a pair of methods, one to set and the other to retrieve the property's value.  These associations are created through the associateRecordIvar:withProperty: and associateRecordSelectors::withProperty: methods.  You can mix and match associations within a record object such that some properties are associated with instance variables and others are associated with method pairs, but a single property can only be associated with one variable or one pair of methods.  

For example, let's say you want to access a table that contains information about convicted felons.  Furthermore, you're only interested in a felon's name and the length of his or her sentence.  To accommodate the records in the table you create a class called FelonRecord, for which the interface file might look like this:

@interface FelonRecord : Object
{
   char *name;
   float sentence;
}
...
@end

Having connected to the database and the table (as described in the DBDatabase class and DBEntities protocol descriptions), you would create a DBBinder object, set the record prototype, and associate the appropriate properties with the designated instance variables:

DBDatabase myDB;
id felonTable;
id nameProp, sentenceProp;
List *propList = [[List alloc] initCount:2];
DBBinder *aBinder;

/* Get the database, entity, and properties.  */
myDB = [DBDatabase findDatabaseNamed:"Crime Data" connect:YES];
felonTable = [myDB entityNamed:"Convicts"];
nameProp = [felonTable propertyNamed:"Name"];
sentenceProp = [felonTable propertyNamed:"Sentence Length"];
[propList addObject:nameProp];
[propList addObject:sentenceProp];

/* Initialize the binder.  */
aBinder = [[DBBinder alloc] initForDatabase:myDB
                            withProperties:propList
                            andQualifier:nil];

/* Set the container, record prototype, and associations.  */
[aBinder setContainer:[[List alloc] init]];
[aBinder setRecordPrototype:[[FelonRecord alloc] init];
[aBinder associateRecordIvar:"name" withProperty:nameProp];
[aBinder associateRecordIvar:"sentence" withProperty:sentenceProp];

The DBBinder is now ready to fetch records from the table (as described in the following section).  

The other approach to creating a record object prototype requires less work and is more adaptable, but it's also less controllable.  It centers around the method createRecordPrototype.  When a DBBinder receives a createRecordPrototype message, it creates and assembles, while you wait, a class (by default, a subclass of Object) that will be used to create record objects.  This new class defines a set of instance variables that match, in number, name, and type, the properties that the DBBinder knows about (as set through the methods described in the previous section, and possibly modified by addProperty: and removePropertyAt:).  When a record is fetched, an instance of the class is created and its instance variables are bound to the record's properties.  Fetching (through the fetch method) automatically invokes createRecordPrototype, thus you needn't invoke it yourself.  

You can prepare the dynamic record class through two DBBinder class methods:

·	setDynamicRecordClassName: takes a string argument that's used to name the class that DBBinder will create; by default, DBBinder gives the class an arbitrary, but unique, name.  The argument that you pass must itself be a unique class nameÐit mustn't name an existing class.

·	setDynamicRecordSuperclassName: also takes a string argument that names a class, but for this method the named class must exist.  It's used as the superclass for the class that DBBinder will create (which, as mentioned above, is Object by default).  This is of particular use if you've created a class whose set of instance variables are known to match, to some extent, the properties in the table that you're binding to.  If the set isn't complete, the subclass (the class that DBBinder will create) will be given a sufficient number of additional instance variables.  

	Warning:	Since these are class methods, invoking either of them will affect all subsequent invocations of createRecordPrototype for all DBBinder instances.  Classes that were previously created are unaffected.

Of the two approaches, the setRecordPrototype: method takes priority.  Reinforcing this, you shouldn't send createRecordPrototype to a DBBinder that has previously received a setRecordPrototype: message.  

Using a DBBinder

The point of all this, of course, is to gain access to the data in the actual database.  Having set up your DBBinder, you can command it to retrieve data through the select, selectWithoutFetching, and fetch methods (select performs a select and a fetch; selectWithoutFetching just selects).  The insert, update, and delete methods write data back to the database.  In addition, the evaluateString: method can be used to command the adaptor associated with the DBBinder's DBDatabase to evaluate the given string, and thereby produce data or modify data.

After fetching data into a DBBinder's record objects, you can point to a particular record by positioning the ªcursorº in the container.  This is done through the DBCursorPositioning protocol methods such as setNext and setTo:.  (If the DBBinder doesn't have a container, then only the setNext method can be used; in this case, setNext causes a fetch to be performed.) 

Having positioned the cursor, you can retrieve a DBValue object from the pointed-to record for a particular property through the valueForProperty: method.  You can then examine and modify the DBValue; any changes you make will be imprinted on the record in the DBBinder and will be written back to the database when the DBBinder receives an update message.  

The DBBinder class also provides an asynchronous fetch mechanism, provoked by the fetchInThread method.  When the DBBinder receives a fetchInThread message, it creates a separate thread in which the fetch is performed.  (Note that asynchronous fetching requires containers.)  To check on the progress of a threaded fetch, use the method checkThreadedFetchCompletion:.

Qualification

You can give a DBBinder a DBQualifier object through the setQualifier: or initForDatabase:withProperties:andQualifier: method.  The DBQualifier is applied to data that's obtained through DBBinder's fetch and select methods; note, however, that it isn't used by evaluateString:.

Instance Variables

id database;

id recordPrototype;

id container;

id delegate;

database	The DBDatabase object with which this DBBinder is associated.

recordPrototype 	A template for the DBBinder's record objects.

container 	The repository for record objects.

delegate 	The receiver of notification messages.

Adopted Protocols

DBCursorPositioning	- setFirst
- setNext
- setPrevious
- setLast
- setTo:
- currentPosition

Method Types

Initializing	- init
- initForDatabase:withProperties:andQualifier:
- free

Connecting to a database	- database
- setDatabase:

Managing properties	- getProperties:
- setProperties:
- addProperty:
- removePropertyAt:

Managing the qualifier	- qualifier
- setQualifier:

Managing the container	- container
- setContainer:
- setFlushEnabled:
- isFlushEnabled
- setFreeObjectsOnFlush:
- areObjectsFreedOnFlush

Managing the record prototype	+ setDynamicRecordSuperclassName:
+ setDynamicRecordClassName:
- setRecordPrototype:
- createRecordPrototype
- ownsRecordPrototype
- recordPrototype
- associateRecordIvar:withProperty:
- associateRecordSelectors::withProperty:
- valueForProperty:

Ordering and ignoring records	- addRetrieveOrder:for:
- removeRetrieveOrderFor:
- retrieveOrderFor:
- positionInOrderingsFor:
- ignoresDuplicateResults
- setIgnoresDuplicateResults:

Accessing the database	- fetch
- select
- selectWithoutFetching
- insert
- update
- delete
- evaluateString:
- adaptorWillEvaluateString:

Fetching in a thread	- fetchInThread
- cancelFetch
- checkThreadedFetchCompletion:

Limiting a fetch	- setMaximumRecordsPerFetch:
- maximumRecordsPerFetch
- recordLimitReached

Using the shared cursor for several binders
- setSharesContext:
- sharesContext

Managing general resources	- reset
- flush
- scratchZone

Appointing a delegate	- delegate
- setDelegate:

Archiving	- read:
- write:

Class Methods

setDynamicRecordClassName:

+ setDynamicRecordClassName:(const char *)aName

Sets the name of the record class that's dynamically created and assembled by the createRecordPrototype method.  The argument must not name an existing class; if it does, invocations of createRecordPrototype will fail.  An argument of NULL erases the previously established class name.  Lacking the instruction provided by this method, the DBBinder class creates a class name that's arbitrary and unique.  The dynamic record class mechanism only applies to DBBinder objects that have no prototype record objects; in other words, it applies only to DBBinders that haven't received a setRecordPrototype: message.  See the class description above for a detailed description of the dynamic record class mechanism.  Returns self, regardless of the viability of the argument.

See also:  + setDynamicRecordSuperclassName:, - setRecordPrototype:

setDynamicRecordSuperclassName:

+ setDynamicRecordSuperclassName:(const char *)aName

Identifies, by name, the class that's used as the superclass of the record classes that are created by createRecordPrototype.  The argument must name an existing class; if it doesn't, invocations of createRecordPrototype will fail.  By default, dynamic record classes are subclasses of Object; an argument of NULL to this method will return the superclass to the default.  The dynamic record class mechanism only applies to DBBinder objects that have no prototype record objects; in other words, it applies only to DBBinders that haven't received a setRecordPrototype: message.  See the class description above for a detailed description of the dynamic record class mechanism.  Returns self, regardless of the viability of the argument.

See also:  + setDynamicRecordClassName:, - setRecordPrototype:

Instance Methods

adaptorWillEvaluateString:

- (BOOL)adaptorWillEvaluateString:(const unsigned char *)aString

Returns YES if the adaptor associated with the DBBinder's DBDatabase object will accept the given string for evaluation (as determined by sending bionder:willEvaluateString: to the DBBinder's delegate), otherwise returns NO.  

See also:  - binder:willEvaluateString: (DBBinder delegate)

addProperty:

- addProperty:anObject

Adds the given object (which should conform to the DBProperties protocol) to the DBBinder's list of properties that it's interested in.  The list can't contain duplicates; if the property is already present, the addition isn't performed.  The return value should be ignored.

Typically, you only use this method if you're building the DBBinder's property list incrementally, and so will rely on the DBBinder to create a record class dynamically.  If you're setting your own prototype record object (through setRecordPrototype:), you should, rather than use this method, inform the DBBinder of its properties all at once, through initForDatabase:withProperties:andQualifier: or setProperties:.

See also:  - setProperties:, - getProperties:, - removePropertyAt:

addRetrieveOrder:for:

- addRetrieveOrder:(DBRetrieveOrder)anOrder for:(id <DBProperties>)aProperty

Establishes the order in which records are retrieved from the database (and stored in the DBBinder's container).  Using the value of the aProperty property as a retrieval ªkey,º records are retrieved in least-to-greatest or greatest-to-least order, as anOrder is DB_AscendingOrder or DB_DescendingOrder.  If anOrder is DB_NoOrder, the default, the property is removed from the retrieval order scheme.  Returns self.

You can invoke this method for as many properties as you choose, but the order in which the invocations are performed is important:  The first invocation establishes the primary retrieval order property, the second establishes the secondary such property, and so on.  If two or more records have the same value for their primary properties, their order is determined according to the values of their secondary properties.  If they still can't be distinguished, the decision falls to the tertiary properties, and so on.  

Note well that it's the adaptorÐnot the DBBinderÐthat retrieves records.  If the adaptor that you're using doesn't support the notion of an ordered retrieval, then this method is for naught.

See also:  - retrieveOrderFor:, - removeRetrieveOrderFor:, - positionInOrderingsFor:

areObjectsFreedOnFlush

- (BOOL)areObjectsFreedOnFlush

Returns YES if the objects in the DBBinder's container are freed when the DBBinder is flushed, otherwise returns NO.  Flushing is explained in the description of the flush method.  By default, the objects are freed.

See also:  - setFreeObjectsOnFlush:, - setFlushEnabled:

associateRecordIvar:withProperty:

- associateRecordIvar:(const char *)variableName
withProperty:(id <DBProperties>)aProperty

Associates the record object instance variable named variableName with the given property such that when a record is fetched from the database, the value of the named instance variable (in the record object that's created to hold the record) is set to the value at the property.  The property's value is coerced, if possible, to match the data type of the instance variable.  If aProperty isn't in the DBBinder's list of properties, the association isn't made and nil is returned, otherwise non-nil is returned.

You should only invoke this method if you're setting your own prototype record object (through the setRecordPrototype: method).  Furthermore, the prototype record must already be set when you invoke this method, and it must contain an instance variable with the given name.  Failing these, the association isn't made (although the return value will still be non-nil).

Rather than associate a property with an instance variable, you can associate it with a pair of instance methods, through the associateRecordSelectors:withProperty: method.  However, a single property can be associated with only one instance variable or one method pair; invoking this method with a particular property undoes the effect of a previous invocation of this or of the associateRecordSelectors:withProperty: method for that property.

See also:  - associateRecordSelectors::withProperty:

associateRecordSelectors::withProperty:

- associateRecordSelectors:(SEL)set 
:(SEL)get 
withProperty:(id <DBProperties>)aProperty

Associates the record object instance methods set and get with the given property such that when a record is fetched from the database, the value at the property is set through the set method, and when the record is written back to the database, the value is retrieved through the get method.  Either or both of the selector arguments may be NULL.  If non-NULL, the set method must take exactly one argument, the value that's being set; the get method must take no arguments.  The data type of the value returned by the get method should match that of the set method's argument.

You should only invoke this method if you're setting your own prototype record object (through the setRecordPrototype: method).  Furthermore, the prototype record must have already been set, and the object must respond to the set and get methods (if they're non-NULL).  If it doesn't respond, or if aProperty isn't in the DBBinder's list of properties, the association isn't made and nil is returned.  Otherwise, the method returns non-nil.

Rather than associate a property with a pair of methods, you can associate it with an instance variable, through the associateRecordIvar:withProperty: method.  However, a single property can be associated with only one instance variable or one method pair; invoking this method with a particular property undoes the effect of a previous invocation of this or of the associateRecordIvar:withProperty: method for that property.

See also:  - associateRecordIvar:withProperty:

cancelFetch

- cancelFetch

Interrupts an asynchronous fetch.  You can also use this method after a successful synchronous fetch to ensure that idle resources are reclaimed.

See also:  - fetchInThread, - fetch, - fetchDone: (DBDatabase)

checkThreadedFetchCompletion:

- checkThreadedFetchCompletion:(double)timeout

If you're performing an asynchronous fetch but you're not using the Application Kit's event loopÐwhich is generally not a particularly safe thing to doÐyou should invoke this message (after invoking fetchInThread) to ensure that the delegate message binderDidFetch: is sent.  The argument is the maximum amount of time, in seconds, to wait before returning.  Returns nil (and the message isn't sent) if the time limit expires before the fetch completes, otherwise returns self.

See also:  - fetchInThread

container

- (id <DBContainers>)container

Returns the DBBinder's container object, as set through setContainer:.  The container, which must conform to the DBContainers protocol, holds the record objects that are created when the DBBinder fetches data.  A DBBinder has no default container and can operate without one, although this impedes some of the object's functionality.  Lacking a container, a DBBinder can't perform an asynchronous fetch, and its cursor can only be positioned through the setNext method.  

See also:  - setContainer:

createRecordPrototype

- createRecordPrototype

Creates and assembles a class that's used to create record objects.  The class is given sufficient instance variables to hold the DBBinder's properties (one instance variable per property).  By default, the name of the class that's created is arbitrary and unique and its superclass is Object.  You can change these settings through the setDynamicRecordClass: and setDynamicRecordSuperclass: class methods.  This method has no effect and returns nil under the following conditions:

·	If the DBBinder's current prototype record object isn't nil.
·	If the DBBinder has no properties.
·	If the name set through setDynamicRecordClass: names an existing class.
·	If the class named by setDynamicRecordSuperclass: doesn't exist.

Upon success, this method returns the class that it created.  

This method is automatically invoked when the DBBinder fetches data, thus you needn't invoke it directly.  In general, it's a good idea to never invoke this method; however, if you doÐfor example, to examine the return valueÐyou should send a setRecordPrototype:nil message to the DBBinder before the next fetch to ensure that the correct class will be assembled.  

See also:  + setDynamicRecordClass:, + setDynamicRecordSuperclass:

database

- (DBDatabase *)database

Returns the DBDatabase object that's associated with the DBBinder.

See also:  - initForDatabase:withProperties:andQualifier:, - setDatabase:

delegate

- delegate

Returns the object that will receive notification messages for the DBBinder.

See also:  - setDelegate:

delete

- delete

Deletes from the database each of the DBBinder's record objects.  

Before the operation begins, a binderWillDelete: message is sent to the DBBinder's delegate (with the DBBinder as the argument); if the delegate message returns NO, then the deletion isn't performed and this method returns nil.  After all the records have been processed, the DBBinder is flushed.  If the records were successfully deleted, a binderDidDelete: message is sent to the delegate and self is returned, otherwise the delegate message isn't sent and nil is returned.  

As each record is deleted, one of two messages is sent to the container's delegate (if the DBBinder has a container, if the container has a delegate, and if the delegate implements the method):

·	binder:didAcceptObject: if the record was deleted.
·	binder:didRejectObject: is sent if the record couldn't be deleted.

For both methods, the first argument is the DBBinder and the second is the record object.  The values returned by these methods are ignored.

evaluateString:

- (BOOL)evaluateString:(const unsigned char *)aString

Tells the adaptor to evaluate and execute the commands that are encoded in aString.    The DBBinder's qualifier isn't applied to the evaluation.

Before the evaluation is performed, a binder:willEvaluateString: message is sent to the DBBinder's delegate.  If the delegate message returns NO, then the evaluation isn't performed and this method immediately returns NO.  

 The DBBinder is then flushed, and the evaluation is performed by sending an evaluateString: message to the DBDatabase, passing aString as the argument.  If the DBDatabase message returns NO, then this method returns NO, otherwise a binder:didEvaluateString: message is sent to the delegate and YES is returned.

fetch

- fetch

Fetches records from the database, forms a record object for each, and places the record objects in the DBBinder's container.  If the binder has no container,  you should use the setNext method, rather than this one, to fetch data.

Before the fetch begins, the DBBinder's delegate is sent a binderWillFetch: message; after, it's sent binderDidFetch:.  If binderWillFetch: returns NO, the fetch isn't performed and this method immediately returns nil.  

As each record of data is fetched, a copy of the DBBinder's prototype record object is created to hold the data.  If the DBBinder's prototype record hasn't been set, a class is dynamically assembled to fill the need, as explained in the description of createRecordPrototype.

The fetch continues until there's no more data to retrieve, or until the record limit (as set through the setMaximumRecordsPerFetch: method) has been reached.  

After the fetch has ended, the DBBinder's cursor is set to the first record in the container (or to the single fetched record if there is no container) and self is returned.  If there was no data to fetch, or if there's a fetch in progress (and the DBBinder has a container), the cursor isn't set and nil is returned.

If the fetch ended by exhausting the source dataÐin other words, it didn't end because the record limit was reachedÐyou should then invoke cancelFetch to reclaim resources that were used during the fetch.  Use the recordLimitReached method to test whether the fetch ended because it reached the limit while there was more data to fetch.

fetchInThread

- fetchInThread

Fetches data asynchronously from the database by performing the fetch in a separate thread.  The general mechanism and conditions are as described in the fetch method, but with these differences:

·	An asynchronous fetch only works if the DBBinder has a container.  

·	You shouldn't invoke cancelFetch after invoking this method unless you actually want to abort the fetch.

·	The record limit set through setMaximumRecordsPerFetch:has no effect on an asynchronous fetch.

If there is no container, or if the binderWillFetch: delegate message returns NO, then the fetch isn't performed and this method returns nil.  Otherwise, this method returns self while the fetch proceeds in the background.  When the fetch is complete, the binderDidFetch: method is sent to the delegate.

If you're not using the Application Kit's main event loop, then you probably don't want to fetch asynchronouslyÐthere are any number of things that you can do, in this situation, that will make your application hang.  But if you're feeling lucky you should note that this method, when run without the App Kit, should be followed by an invocation of checkThreadedFetchCompletion:.  This synchronizes the fetch thread with the main thread, and ensures that the binderDidFetch: message is sent.  Good luck. 

To be used in an asynchronous fetch, the DBBinder's container must be thread-safe (it must be re-entrant).  Alternatively, if you limit yourself to DBCursorPositioning methods, such as setTo: and setNext:, you can access the container regardless of the type of fetch employed.

See also:  - fetch, - cancelFetch, - checkThreadedFetchCompletion:

flush

- (BOOL)flush

If flushing is enabled, this empties the DBBinder's container.  Furthermore, if the DBBinder has been told to free-on-flush, the records that were in the container are freed and the prototype record object is set to nil.  By default, both flushing and free-on-flush are enabled.  Returns YES if flushing is enabled, NO if not.

This method always interrupts a fetch, if one is in progress, whether or not flushing is enabled.  

The following DBBinder methods may cause flush to be invoked:

- evaluateString:
- selectWithoutFetching
- insert
- update
- delete
- setProperties:
- reset
- free

See also:  - setFlushEnabled:, - setFreeOnFlush:

free

- free

Frees the DBBinder and its records.  If the DBBinder owns the prototype record object, it too is freed.  

getProperties:

- (List *)getProperties:(List *)aList

Fills aList with the DBBinder's properties, then returns the List directly and by reference.  The order of the properties in the List is that by which they were added to the DBBinder.  You mustn't free the contents of aList, although you may free the List itself.  

See also:  - initForDatabase:withProperties:andQualifier:, - setProperties:, - addProperty

ignoresDuplicateResults

- (BOOL)ignoresDuplicateResults

Returns YES if the DBBinder is set to ignore duplicate records during a select.  The default is NO.  It's up to the adaptor to support this (the Oracle and Sybase adapters supplied with the Database Kit do).

See also:  - setIgnoresDuplicateResults:

init

- init

The designated initializer for the DBBinder class, init initializes and returns the DBBinder.  All the objects that the DBBinder owns or knows of, such as its container, properties, DBDatabase, and DBQualifier are set to nil.  Its boolean attributes are set as follows:

Attribute	Value

flushing enabled?	YES
frees properties on flush?	YES
ignores duplicates?	NO
shares context?	NO

See also:  - initForDatabase:withProperties:andQualifier

initForDatabase:withProperties:andQualifier:

- initForDatabase:aDBDatabase
withProperties:(List *)propertyList 
andQualifier:(DBQualifier *)aDBQualifier

Invokes init and then sets the DBBinder's DBDatabase, properties, and DBQualifier as given by the arguments.  The properties in propertyList are added to the DBBinder's own List, thus the argument may be freed.

See also:  - init

insert

- insert

Inserts into the database each of the DBBinder's record objects.

Before the operation begins, a binderWillInsert: message is sent to the DBBinder's delegate (with the DBBinder as the argument); if the delegate message returns NO then the insertion isn't performed and nil is immediately returned by this method.  After all the records have been processed, the DBBinder is flushed.  If the records were successfully inserted, a binderDidInsert: message is sent to the delegate and self is returned, otherwise the delegate message isn't sent and nil is returned.  

As each record is inserted, one of two messages is sent to the container's delegate (if the DBBinder has a container, if the container has a delegate, and if the delegate implements the appropriate method):

·	binder:didAcceptObject: if the record was inserted.
·	binder:didRejectObject: is sent if the record couldn't be inserted.

For both methods, the first argument is the DBBinder and the second is the record object.  The values returned by these methods are ignored.

isFlushEnabled

- (BOOL)isFlushEnabled

Returns YES if the DBBinder has flushing enabled, otherwise return NO.  The default is YES.  See the description of the flush method for more information.  (Note that sharing a cursor is incompatible with flushing, so setSharesContext: has the side effect of disabling flushing.)

See also:  - flush, - setFlushEnabled:, - setSharesContext:

maximumRecordsPerFetch

- (unsigned int)maximumRecordsPerFetch

Returns the maximum number of records that will be retrieved during a synchronous fetch, as set through the setMaximumRecordsPerFetch: method.  By default, this limit is set to DB_NoIndex, which imposes no limit.

See also:  - setMaximumRecordsPerFetch:, - recordLimitReached, - fetch

ownsRecordPrototype

- (BOOL)ownsRecordPrototype

Returns YES if the DBBinder owns its prototype record objectÐin other words, if it will create a record class for you (when createRecordPrototype is invoked).  If you've set the prototype record object yourself, through setRecordPrototype:, then this returns NO.

positionInOrderingsFor:

- (unsigned int)positionInOrderingsFor:(id <DBProperties>)aProperty

Returns an integer that indicates the level (primary, secondary, tertiary, and so on) at which the given property is used to order the records that are retrieved from the database.  The ordering position of a particular property is the order in which it was added to the ordering mechanism (amongst the currently ªactiveº ordering properties) through the addRetrieveOrder:for: method.  A return of DB_NoIndex means that the property isn't used in the ordering mechanism.

See also:  - addRetrieveOrder:For:

qualifier

- (DBQualifier *)qualifier

Returns the DBQualifier object that was set through setQualifier: or initForDatabase: withProperties:andQualifier:.  The qualifier is used to qualify values during a select.

See also:  - setQualifier:, - initForDatabase:withProperties:andQualifier:

read:

- read:(NXTypedStream *)stream

Reads the DBBinder from the typed stream stream.  Returns self.

recordLimitReached

- (BOOL)recordLimitReached

If the previous fetch was stopped because the DBBinder's record limit (as set through the setMaximumRecordsPerFetch: method) was reached, then this returns YES.  By default, this returns NO; the flush method will also set this to return NO, whether or not flushing is enabled.  See the description of the fetch method for an example of the use this method.

See also:  - setMaximumRecordsPerFetch:, - maximumRecordsPerFetch, - fetch

recordPrototype

- recordPrototype

Returns the DBBinder's prototype record object.  If you've set the object yourself, through setRecordPrototype:, then that object is returned.  Otherwise, this returns nil unless you've previously invoked createRecordPrototype directly, or unless this is called from within a subclass implementation of fetch.

See also:  - setRecordPrototype, - createRecordPrototype

removePropertyAt:

- removePropertyAt:(unsigned int)index

Removes the property at the given index.  To find the index of a particular property, get the DBBinder's List of properties through the getProperties: method, and then ask for the index by sending indexOf: to the List, passing the property as the argument.  Returns the property (or nil if there was none).

See also:  - setProperties:, - addProperty:

removeRetrieveOrderFor:

- removeRetrieveOrderFor:(id <DBProperties>)aProperty

Removes the given property from the list of properties that are used to sort records as they're being fetched.  The property's retrieve order constant is set to DB_NoOrder.  Returns nil if the property hadn't previously been added to the record-sorting list (if it hadn't previously received an addRetrieveOrderFor: message), otherwise self is returned.  

See also:  - addRetrieveOrderFor:, - positionInOrderingsFor:

reset

- reset

Restores the DBBinder to a virgin state.  The DBBinder is first flushed (which cancels a fetch, if one is in progress), then the objects that it has allocated, and any that you've allocated in the scratch zone, are freed.  The setProperties: and free methods automatically cause a reset.

See also:  - flush, - scratchZone

retrieveOrderFor:

- (DBRetrieveOrder)retrieveOrderFor:(id <DBProperties>)aProperty

Returns a constant that indicates the order in which records are retrieved when aProperty is used as a retrieval key (see the addRetrieveOrder:for: method for a further explanation).  The retrieval order constants are:

Constant	Meaning

DB_NoOrder	The property isn't part of the ordering scheme
DB_AscendingOrder	Least to greatest
DB_DescendingOrder	Greatest to least

See also:  - addRetrieveOrder:for:, - positionInOrderingsFor:

scratchZone

- (NXZone *)scratchZone

Returns the zone in which the DBBinder allocates the objects that it owns.  The objects in the zone are freed during a reset; the zone is made public so you can use it to allocate your own supporting objects and have them freed during a reset as well.  Note that the zone may be different after each reset.

See also:  - reset

select

- select

Selects and fetches data from the database.  First, selectWithoutFetching is invoked; if that returns nil, then this returns nil.  If the method was successful, then fetch is invoked; the value returned by fetch is returned by this method.  

See also:  - selectWithoutFetching, - fetch

selectWithoutFetching

- selectWithoutFetching

Selects records from the database, using the DBBinder's qualifier (as set through setQualifier: or initForDatabase:withProperties:andQualifier:) to qualify the records that are selected.

Before the operation begins, a binderWillSelect: message is sent to the DBBinder's delegate (with the DBBinder as the argument); if the delegate message returns NO, then the select isn't performed and nil is immediately returned by this method.  Otherwise, the DBBinder is flushed and the data is selected.  If the select was successful, a binderDidSelect: message is sent to the delegate and self is returned, otherwise the delegate message isn't sent and nil is returned.  

If the DBBinder is set to ignore duplicate results, only the first of duplicate records will be selected.

See also:  - select, - setIgnoreDuplicateResults

setContainer:

- setContainer:(id <DBContainers>)anObject

Sets the container that's used to store record objects.  The argument must either adopt the DBContainers protocol, or it can be a List objectÐDBBinder defines a category of List that allows its instances, and those of its subclasses, to pose as DBContainers-conforming objects.  Most DBBinders are well served using a List as a container.  For more on the theory and practice of containment, see the class description, above.

Returns the previous container.  

setDatabase:

- setDatabase:(DBDatabase *)aDatabase

Sets the DBBinder's database.  Returns the previous DBDatabase object.

setDelegate:

- setDelegate:anObject

Sets the object that receives notification messages for the DBBinder.

setFlushEnabled:

- setFlushEnabled:(BOOL)flag

Establishes whether the DBBinder is capable of being flushed, as explained in the description of the flush method.  The default is YES.

See also:  - flush, - setFreeObjectOnFlush:

setFreeObjectsOnFlush:

- setFreeObjectsOnFlush:(BOOL)flag

Establishes whether the DBBinder will free its records when it's flushed.  Setting this to YES is effective only if the DBBinder is capable of being flushed, as established by the setFlushEnabled: method.  The default is YES (the default flush-enablement is also YES).

See also:  - flush, - setFlushEnabled:

setIgnoresDuplicateResults:

- setIgnoresDuplicateResults:(BOOL)flag

Establishes whether duplicate records are ignored during a select.  The default is NO.  It's up the adaptor to support this; the Oracle and Sybase adapters supplied with the Database Kit do.

See also:  - ignoresDuplicateRecords, - selectWithoutFetching

setMaximumRecordsPerFetch:

- setMaximumRecordsPerFetch:(unsigned int)limit

Sets, to limit, the maximum number of records that will be retrieved during a fetch.  The limit only applies to synchronous fetches; the asynchronous fetch method fetchInThread ignores the record limit.

See also:  - maximumRecordsPerFetch, - recordLimitReached, - fetch

setProperties:

- (List *)setProperties:(List *)aList

Resets the DBBinder and then adds to it the properties in aList.  Returns the argument.  

See also:  - getProperties:, - addProperty:, - removePropertyAt:

setQualifier:

- setQualifier:(DBQualifier *)aQualifier

Sets the qualifier that's used during a select.  Returns self.

See also:  - qualifier

setRecordPrototype:

- setRecordPrototype:anObject

Sets the object that's copied to store the results of a fetch.  See the class description for a full explanation of the record prototype object.

See also:  - recordPrototype, - createRecordPrototype

setSharesContext:

- setSharesContext:(BOOL)flag

Establishes whether the DBBinder shares its cursor with other DBBinder objects.  The default is NO.  Making a DBBinder share its cursor disables flushing.  Returns self.

Shared cursor behavior depends on the implementation of the adaptor rather than the database; it's provided in both the Oracle and the Sybase adaptors as a way of achieving atomic updates.  Sharing the cursor also provides a slightly more efficient use of memory. 

See also:  - sharesContext

sharesContext

- (BOOL)sharesContext

Returns YES if the DBBinder shares its cursor with other DBBinders, otherwise returns NO.

See also:  - setSharesContext:

update

- update

Copies the values in the DBBinder's record objects into the appropriate records in the database.

Before the operation begins, a binderWillUpdate: message is sent to the DBBinder's delegate (with the DBBinder as the argument); if the delegate message returns NO, then the update isn't performed and nil is immediately returned by this method.  After all the records have been processed, the DBBinder is flushed.  If the records were successfully updated, a binderDidUpdate: message is sent to the delegate and self is returned, otherwise the delegate message isn't sent and nil is returned.  

As each record is updated, one of two messages is sent to the container's delegate (if the DBBinder has a container, if the container has a delegate, and if the delegate implements the appropriate method):

·	binder:didAcceptObject: if the record was updated.
·	binder:didRejectObject: is sent if the record couldn't be updated.

For both methods, the first argument is the DBBinder and the second is the record object.  The values returned by these methods are ignored.

valueForProperty:

- (DBValue *)valueForProperty:(id <DBProperties>)aProperty

Returns a DBValue object for the given property of the currently pointed-to record.  Use the DBCursorPositioning methods, such as setNext and setTo:, to set the cursor to point to a particular record.  The object that's returned is owned by the DBBinder and shouldn't be freed.

write:

- write:(NXTypedStream *)stream

Writes the DBBinder to the typed stream stream.  Returns self.

Methods Implemented by the Delegate

binder:didEvaluateString:

- binder:aBinder didEvaluateString:(const unsigned char *)aString

Invoked after the given string has been successfully evaluated by DBBinder's evaluateString: method.  The return value is ignored.  

binder:willEvaluateString:

- (BOOL)binder:aBinder willEvaluateString:(const unsigned char *)aString

Invoked before the given string is evaluated by DBBinder's evaluateString: method.  A return of NO will thwart the evaluation.  

binderDidDelete:

- binderDidDelete:aBinder

Invoked after the DBBinder has successfully deleted records through the delete method.  The return value is ignored.  

binderDidFetch:

- binderDidFetch:aBinder

Invoked after the DBBinder has successfully fetched records through the fetch or fetchInThread method.  The return value is ignored.  

binderDidInsert:

- binderDidInsert:aBinder

Invoked after the DBBinder has successfully inserted records through the insert method.  The return value is ignored.  

binderDidSelect:

- binderDidSelect:aBinder

Invoked after the DBBinder has successfully selected data through the selectWithoutFetching method.  The return value is ignored.  

binderDidUpdate:

- binderDidUpdate:aBinder

Invoked after the DBBinder has successfully updated the database through the update method.  The return value is ignored.  

binderWillDelete:

- (BOOL)binderWillDelete:aBinder

Invoked before the DBBinder attempts to delete records from the database through the delete method.  A return of NO will thwart the attempt.  

binderWillFetch:

- (BOOL)binderWillFetch:aBinder

Invoked before the DBBinder attempts to fetch data through the fetch or fetchInThread method.  A return of NO will thwart the attempt.  

binderWillInsert:

- (BOOL)binderWillInsert:aBinder

Invoked before the DBBinder attempts to insert records into the database through the insert method.  A return of NO will thwart the attempt.  

binderWillSelect:

- (BOOL)binderWillSelect:aBinder

Invoked before the DBBinder attempts to select data from the database through the selectWithoutFetching method.  A return of NO will thwart the attempt.  

binderWillUpdate:

- (BOOL)binderWillUpdate:aBinder

Invoked before the DBBinder attempts to update the database through the update method.  A return of NO will thwart the attempt.